**Final Project** (##) **Claire Oudea (f00813g)** (#) Motivational Image ***Ship on Stormy Seas by Ivan Aivazovsky***
const int num_threads = std::max(1u, std::thread::hardware_concurrency());
std::vector> samplers;
samplers.reserve(num_threads);
for (int i = 0; i < num_threads; ++i) samplers.push_back(m_sampler->clone());
std::atomic rows_done{0};
std::vector threads;
threads.reserve(num_threads);
auto worker = [&](int tid) {
auto &local_sampler = *samplers[tid];
thread_local std::mt19937 rng(std::random_device{}() + tid);
std::uniform_real_distribution dist(0.0f, 1.0f);
int rows_per_thread = (H + num_threads - 1) / num_threads;
int y0 = tid * rows_per_thread;
int y1 = std::min(H, y0 + rows_per_thread);
for (int y = y0; y < y1; ++y) {
for (int x = 0; x < W; ++x) {
Color3f pixel_color(0.0f);
// local_sampler.set_base_seed(randf());
for (int s = 0; s < m_num_samples; ++s) {
float rx = dist(rng);
float ry = dist(rng);
Vec2f pixel_sample(x + rx, y + ry);
Ray3f ray = m_camera->generate_ray(pixel_sample);
if (m_integrator)
pixel_color += m_integrator->Li(*this, local_sampler, ray);
else
pixel_color += recursive_color(ray, 0);
}
pixel_color /= float(m_num_samples);
image(x,y) = pixel_color;
}
int done = ++rows_done;
progress.step();
}
};
(##) Discovery Cluster
(##) Simple extra geometry: Cube
(##) Environment Map Emitter (with importance sampling)
if (!scene.intersect(ray_recursive, hit)) {
// Iterate over all infinite emitters (env map)
SurfaceGroup infinite_emitters = scene.infiniteEmitters();
for (int i=0; i < infinite_emitters.child_num(); ++i) {
auto infinite_emitter = infinite_emitters.child_by_index(i);
float misWeight_mats;
if (depth == 0 || srec.is_specular)
misWeight_mats = 1.f;
else {
float pdf_ems = scene.emitters().child_prob() * infinite_emitter->pdf(ray_recursive.o, ray_recursive.d);
misWeight_mats = pdf_mats / (pdf_mats + pdf_ems);
}
L += misWeight_mats * throughput * infinite_emitter->eval(ray_recursive.o, ray_recursive.d, hit);
Color3f printtestcolor = infinite_emitter->eval(ray_recursive.o, ray_recursive.d, hit);
spdlog::info("infinite_emitter->eval: {} {} {}", printtestcolor[0], printtestcolor[1], printtestcolor[2]);
}
break;
}
// box blur
int radius = int(blur);
Color3f sum(0.0f);
int count = 0;
for (int dx = -radius; dx <= radius; dx++)
{
for (int dy = -radius; dy <= radius; dy++)
{
int x = clamp(cx + dx, 0, image.width() - 1);
int y = clamp(cy + dy, 0, image.height() - 1);
sum += image.at(x, y);
count++;
}
}
return sum / float(count);
Color3f bilinear(float u, float v) const
{
float x = u * (image.width() - 1);
float y = (1.0f - v) * (image.height() - 1);
int x0 = floor(x);
int x1 = std::min(x0 + 1, image.width() - 1);
int y0 = floor(y);
int y1 = std::min(y0 + 1, image.height() - 1);
float tx = x - x0;
float ty = y - y0;
Color3f c00 = image.at(x0, y0);
Color3f c10 = image.at(x1, y0);
Color3f c01 = image.at(x0, y1);
Color3f c11 = image.at(x1, y1);
return (1 - tx) * (1 - ty) * c00
+ tx * (1 - ty) * c10
+ (1 - tx) * ty * c01
+ tx * ty * c11;
}
Color3f bicubic(float u, float v) const
{
float x = u * (image.width() - 1);
float y = (1.0f - v) * (image.height() - 1);
int ix = floor(x);
int iy = floor(y);
Color3f sum(0.0f);
float wsum = 0.0f;
for (int m = -1; m <= 2; m++)
{
float wy = cubic_weight(float(iy + m) - y);
int yy = clamp(iy + m, 0, image.height() - 1);
for (int n = -1; n <= 2; n++)
{
float wx = cubic_weight((ix + n) - x);
int xx = clamp(ix + n, 0, image.width() - 1);
float w = wx * wy;
sum += image.at(xx, yy) * w;
wsum += w;
}
}
return sum / wsum;
}
(##) Captured Environment Map
(##) Final Rendered Image
(##) Challenges
My biggest challenge was debugging my heterogenous volume path tracer.
At some point I generated a very artistic but also very "wrong" cloud.
Since it looked nice, I rendered an artistic version of my final image below:
***Early Prototype***